/*
 * 描          述:  <描述>
 * 修  改   人:  Administrator
 * 修改时间:  2018年5月1日
 * <修改描述:>
 */
package com.tx.core.ddlutil.builder.alter;

import com.tx.core.ddlutil.executor.TableDDLExecutor;
import com.tx.core.ddlutil.model.TableColumnDef;
import com.tx.core.ddlutil.model.TableDef;
import com.tx.core.ddlutil.model.TableIndexDef;
import com.tx.core.exceptions.util.AssertUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 编辑表辅助类<br/>
 * <功能详细描述>
 * 
 * @author  Administrator
 * @version  [版本号, 2018年5月1日]
 * @see  [相关类/方法]
 * @since  [产品/模块版本]
 */
public class AlterTableComparetor {
    
    //日志记录器
    private Logger logger = LoggerFactory.getLogger(TableDDLExecutor.class);
    
    /** 编辑表字段集合 */
    private Map<String, AlterTableColumn> alterTableColumnMap = new HashMap<>();
    
    /** 原表定义 */
    private TableDef sourceTableDef;
    
    /** 表字段 */
    private List<TableColumnDef> targetTableColumns;
    
    /** 表索引 */
    private List<TableIndexDef> targetTableIndexes;
    
    /** 是否需要编辑 */
    private boolean needAlter = false;
    
    /** 是否需要备份 */
    private boolean needBackup = false;
    
    /** 是否需要编辑主键 */
    private boolean needModifyPrimaryKey = false;
    
    /** 主键字段名 */
    private String primaryKey;
    
    /** 编辑表字段 */
    private List<AlterTableColumn> alterTableColumns = new ArrayList<>();
    
    /** 编辑表索引 */
    private List<AlterTableIndexComparetor> alterTableIndexComparetors = new ArrayList<>();
    
    /** <默认构造函数> */
    public AlterTableComparetor() {
        super();
    }
    
    /** <默认构造函数> */
    public AlterTableComparetor(TableDef sourceTableDef) {
        super();
        this.sourceTableDef = sourceTableDef;
    }
    
    /**
     * 对比<br/>
     * <功能详细描述> [参数说明]
     * 
     * @return void [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public void compare() {
        AssertUtils.notNull(sourceTableDef, "sourceTable is null.");
        AssertUtils.notEmpty(targetTableColumns, "targetTableColumns is null.");

        String sourcePrimaryKeyColumnNames = sourceTableDef.getPrimaryKey();
        this.needModifyPrimaryKey = !StringUtils.equalsIgnoreCase(
                sourcePrimaryKeyColumnNames, this.primaryKey);
        if (this.needModifyPrimaryKey) {
            this.needAlter = true;
        }
        
        //对比字段
        compareColumns();
        
        //对比索引
        compareIndexes();
    }
    
    /** 
     * 对比字段
     * <功能详细描述> [参数说明]
     * 
     * @return void [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    private void compareColumns() {
        this.alterTableColumnMap.clear();
        this.alterTableColumns.clear();
        
        for (TableColumnDef sourceColumn : sourceTableDef.getColumns()) {
            AssertUtils.notEmpty(sourceColumn.getName(),
                    "sourceColumn.columnName is empty.");
            
            alterTableColumnMap.put(sourceColumn.getName().toUpperCase(),
                    new AlterTableColumn(sourceColumn));
        }
        for (TableColumnDef targetColumn : targetTableColumns) {
            AssertUtils.notEmpty(targetColumn.getName(),
                    "targetColumn.columnName is empty.");
            
            if (alterTableColumnMap
                    .containsKey(targetColumn.getName().toUpperCase())) {
                alterTableColumnMap
                        .get(targetColumn.getName().toUpperCase())
                        .setTargetColumn(targetColumn);
            } else {
                AlterTableColumn newAlterTableColumn = new AlterTableColumn();
                newAlterTableColumn.setTargetColumn(targetColumn);
                alterTableColumnMap.put(
                        targetColumn.getName().toUpperCase(),
                        newAlterTableColumn);
            }
        }
        for (AlterTableColumn alterColumn : alterTableColumnMap.values()) {
            alterColumn.compare();
            if (alterColumn.isStrictMatch()) {
                continue;
            }
            if (alterColumn.isNeedAlter()) {
                logger.info(
                        "检测到表字段需要升级.tablename:'{}'.columnname:'{}' .remark:'{}'.AlterType:'{}'",
                        this.getSourceTableDef().getName(),
                        alterColumn.getColumnName(),
                        alterColumn.getRemark(),
                        alterColumn.getAlterType());
                
                TableColumnDef sourceColumn = alterColumn.getSourceColumn();
                if (sourceColumn != null) {
                    logger.info(
                            "scol: jdbcType:'{}',size:'{}',scale:'{}',comment:'{}',defaultvalue:'{}',isRequired:'{}'",
                            sourceColumn.getJdbcType(),
                            sourceColumn.getSize(),
                            sourceColumn.getScale(),
                            sourceColumn.getComment(),
                            sourceColumn.getDefaultValue(),
                            sourceColumn.isRequired());
                }
                TableColumnDef targetColumn = alterColumn.getTargetColumn();
                if (targetColumn != null) {
                    logger.info(
                            "tcol: jdbcType:'{}',size:'{}',scale:'{}',comment:'{}',defaultvalue:'{}',isRequired:'{}'",
                            targetColumn.getJdbcType(),
                            targetColumn.getSize(),
                            targetColumn.getScale(),
                            targetColumn.getComment(),
                            targetColumn.getDefaultValue(),
                            targetColumn.isRequired());
                }
                
                this.needAlter = true;
                this.alterTableColumns.add(alterColumn);
            }
            if (alterColumn.isNeedBackup()) {
                this.needBackup = true;
            }
        }
    }
    
    /** 
     * 对比索引<br/>
     * <功能详细描述> [参数说明]
     * 
     * @return void [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    private void compareIndexes() {
        this.alterTableIndexComparetors.clear();

        Map<String, AlterTableIndexComparetor> alterTableIndexComparetorMap = new HashMap<>();
        for (TableIndexDef sourceIndex : sourceTableDef.getIndexes()) {
            AssertUtils.notEmpty(sourceIndex.getName(),
                    "sourceIndex.indexName is empty.");
            alterTableIndexComparetorMap.put(sourceIndex.getName().toUpperCase(),
                    new AlterTableIndexComparetor(sourceIndex));
        }
        for (TableIndexDef targetIndex : targetTableIndexes) {
            AssertUtils.notEmpty(targetIndex.getName(),
                    "targetIndex.indexName is empty.");
            //如果源存在，则设置目标字段
            if (alterTableIndexComparetorMap
                    .containsKey(targetIndex.getName().toUpperCase())) {
                alterTableIndexComparetorMap.get(targetIndex.getName().toUpperCase())
                        .setTargetIndex(targetIndex);
            } else {
                AlterTableIndexComparetor newAlterTableIndexComparetor = new AlterTableIndexComparetor();
                newAlterTableIndexComparetor.setTargetColumn(targetIndex);
                alterTableIndexComparetorMap.put(targetIndex.getName().toUpperCase(),
                        newAlterTableIndexComparetor);
            }
        }
        
        for (AlterTableIndexComparetor alterIndex : alterTableIndexComparetorMap.values()) {
            alterIndex.compare();
            if (alterIndex.isNeedAlter()) {
                this.needAlter = true;
                this.alterTableIndexComparetors.add(alterIndex);
            }
        }
    }
    
    /**
     * @return 返回 sourceTableDef
     */
    public TableDef getSourceTableDef() {
        return sourceTableDef;
    }
    
    /**
     * @param sourceTableDef
     */
    public void setSourceTableDef(TableDef sourceTableDef) {
        this.sourceTableDef = sourceTableDef;
    }
    
    /**
     * @return 返回 targetTableColumns
     */
    public List<TableColumnDef> getTargetTableColumns() {
        return targetTableColumns;
    }
    
    /**
     * @param targetTableColumns
     */
    public void setTargetTableColumns(List<TableColumnDef> targetTableColumns) {
        this.targetTableColumns = targetTableColumns;
    }
    
    /**
     * @return 返回 targetTableIndexes
     */
    public List<TableIndexDef> getTargetTableIndexes() {
        return targetTableIndexes;
    }
    
    /**
     * @param targetTableIndexes
     */
    public void setTargetTableIndexes(List<TableIndexDef> targetTableIndexes) {
        this.targetTableIndexes = targetTableIndexes;
    }
    
    /**
     * @return 返回 needAlter
     */
    public boolean isNeedAlter() {
        return needAlter;
    }
    
    /**
     * @param needAlter
     */
    public void setNeedAlter(boolean needAlter) {
        this.needAlter = needAlter;
    }
    
    /**
     * @return 返回 needBackup
     */
    public boolean isNeedBackup() {
        return needBackup;
    }
    
    /**
     * @param needBackup
     */
    public void setNeedBackup(boolean needBackup) {
        this.needBackup = needBackup;
    }
    
    /**
     * @return 返回 needModifyPrimaryKey
     */
    public boolean isNeedModifyPrimaryKey() {
        return needModifyPrimaryKey;
    }
    
    /**
     * @param needModifyPrimaryKey
     */
    public void setNeedModifyPrimaryKey(boolean needModifyPrimaryKey) {
        this.needModifyPrimaryKey = needModifyPrimaryKey;
    }
    
    /**
     * @return 返回 primaryKeyColumnNames
     */
    public String getPrimaryKey() {
        return primaryKey;
    }
    
    /**
     * @param primaryKey
     */
    public void setPrimaryKey(String primaryKey) {
        this.primaryKey = primaryKey;
    }
    
    /**
     * @return 返回 alterTableColumns
     */
    public List<AlterTableColumn> getAlterTableColumns() {
        return alterTableColumns;
    }
    
    /**
     * @param alterTableColumns
     */
    public void setAlterTableColumns(List<AlterTableColumn> alterTableColumns) {
        this.alterTableColumns = alterTableColumns;
    }
    
    /**
     * @return 返回 alterTableIndexes
     */
    public List<AlterTableIndexComparetor> getAlterTableIndexes() {
        return alterTableIndexComparetors;
    }
    
    /**
     * @param alterTableIndexComparetors
     */
    public void setAlterTableIndexes(List<AlterTableIndexComparetor> alterTableIndexComparetors) {
        this.alterTableIndexComparetors = alterTableIndexComparetors;
    }
}
